# 与项目相关的视图

from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
# 导入分页
from rest_framework.pagination import PageNumberPagination
# 导入模型
from sa.models import Project, User
# 导入序列化器
from sa.serializers.projectSerializer import ProjectInfoSerializer

from django.db.models import Q
from django.http import Http404

import logging

# 日志记录对象
logger = logging.getLogger('django')


# 创建分页类
class LargeResultsSetPagination(PageNumberPagination):
    # 定义了默认每页显示的记录数（即如果用户没有通过 size 参数指定每页大小，则默认每页显示 10 条）
    page_size = 10  # 默认每页显示多少条记录 10条
    page_size_query_param = 'size'  # 每页显示10条 前端控制每页显示条数的参数名（如参数 ?size=10）
    page_query_param = 'page'  # 表示请求第3页 前端发送的查询页码关键字名，默认为"page"（如参数 ?page=3, 第三页）
    max_page_size = 100  # 前端最多能设置的每页显示数量不能超过20条 限制用户通过 size 参数能设置的最大值

    """
    DRF 分页响应格式：
    {
        "count": 100,
        "next": "http://...?page=3",
        "previous": "http://...?page=1",
        "results": [{}, {}, {}...]
    }
    """


class ProjectInfoGenericAPIView(GenericAPIView):
    """管理员 项目信息列表"""
    # 指定序列化器类 拿到序列化器
    serializer_class = ProjectInfoSerializer
    # 指明使用的数据查询集（数据来源）
    # queryset = Project.objects.all().order_by('-id')
    # select_related 优化“单值”关系的查询，例如外键（`ForeignKey`）和一对一关系（`OneToOneField`）
    # prefetch_related 用于优化“多值”关系的查询，例如多对多关系（`ManyToManyField`）和反向的外键关系
    queryset = Project.objects.all().select_related(
        'customer', 'creator').prefetch_related(
        'participants').order_by(
        '-id')
    pagination_class = LargeResultsSetPagination
    permission_classes = [IsAuthenticated]

    def get(self, request):

        # 进入角色判断，不同的角色显示不同的内容
        # values_list  只从数据库获取 role_name 字段，而不是整个 Role 对象
        # flat=True 只需要单个字段时，返回平面列表而不是元组列表
        role_name = request.user.roles.values_list('role_name', flat=True)  # 生成当前用户的角色列表
        # print(role_name)
        # if len(role_name) == 1 and role_name[0] == 'SA_User':
        #     # participants=user 和 participants__in=[user] 效果相同
        #     # .distinct() 确保结果去重（防止同一项目因匹配多个条件重复出现）（因 OR 条件可能导致重复）
        #     project_list = (
        #         self.get_queryset().filter(Q(creator=request.user) |
        #                                    Q(participants=request.user)).distinct())
        if 'RO_Manager' in role_name and 'SA_Manager' not in role_name:
            project_list = self.get_queryset().filter(
                creator__region=request.user.region)
        elif 'SA_Manager' in role_name:
            project_list = self.get_queryset()
        else:
            project_list = []

        # request.query_params 获取 URL 查询参数
        # 定义允许的查询字段列表, 与前端 params 查询字段对应(不包含分页信息)
        # SEARCH_FIELDS = [
        #     'customer_name', 'sa_name',
        #     'sa_region', 'category',
        #     'start_date', 'end_date', 'status']
        # # 循环动态收集参数
        # search_params_dict = {}  # 准备存放多个筛选或查询信息字段的字典
        # # 避免使用多个request.query_params.get
        # for field in SEARCH_FIELDS:
        #     value = request.query_params.get(field)
        #     # 只保留非空参数
        #     if value is not None:
        #         search_params_dict[field] = value
        # print('search_params_dict:', search_params_dict)
        # {'customer_name': 'aaaa', 'sa_name': '', 'start_date': '2025-01-16', 'end_date': '2025-04-16', 'status': 'Ongoing'}

        """ request.query_params 获取 URL 查询参数 """
        # 先处理Q查询,  Q 查询是对象，不能直接使用**展开
        get_customer = request.query_params.get('customer_name')
        if get_customer:
            # 查询 外键字段 customer 关联的 CustomerInfo 表 的 name 字段
            # 查询 SR_No 字段
            project_list = (
                # .distinct() 确保结果去重（防止同一项目因匹配多个条件重复出现）（因 OR 条件可能导致重复）
                project_list.filter(Q(customer__name__icontains=get_customer) |
                                    Q(SR_No__contains=get_customer))).distinct()
        get_user = request.query_params.get('sa_info')
        if get_user:
            project_list = (
                project_list.filter(Q(creator__cn_name__icontains=get_user) |
                                    Q(creator__en_name__icontains=get_user) |
                                    Q(creator__username__icontains=get_user) |
                                    Q(participants__cn_name__icontains=get_user) |
                                    Q(participants__en_name__icontains=get_user) |
                                    Q(participants__username__icontains=get_user))).distinct()
        # print(request.query_params)

        # 再处理普通查询, 可以 ** 展开
        search_params_dict = {}
        get_region = request.query_params.get('sa_region')
        if get_region:
            search_params_dict['creator__region'] = get_region

        get_category = request.query_params.get('category')
        if get_category:
            search_params_dict['category'] = get_category

        get_start_date = request.query_params.get('start_date')
        if get_start_date:
            # __gte 是 Django ORM 的一个查询查找器，表示“大于或等于”
            search_params_dict['start_date__gte'] = get_start_date

        get_end_date = request.query_params.get('end_date')
        if get_end_date:
            # __lte 是 Django ORM 的一个查询查找器，表示“小于或等于”
            search_params_dict['end_date__lte'] = get_end_date

        get_status = request.query_params.get('status')
        if get_status:
            search_params_dict['status'] = get_status

        project_list = project_list.filter(**search_params_dict)
        logger.info(f'查询数据:{search_params_dict}')

        """增加分页处理 对获得的查询集使用 paginate_queryset方法进行数据切片"""
        # 返回当前页的数据切片, 也是一个查询集
        page_queryset = self.paginate_queryset(project_list)
        if page_queryset is not None:
            serializer = self.get_serializer(instance=page_queryset, many=True)
            # 使用 self.get_paginated_response(serializer.data)
            # 标准分页格式 {count, next, previous, results}  前端可获取分页状态
            return self.get_paginated_response(data=serializer.data)
        else:
            serializer = self.get_serializer(instance=project_list, many=True)
            return Response(data=serializer.data)

    def post(self, request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 使用 data=serializer.data，因为结果有关联对象,不能JSON序列化，直接返回id
        return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        # return Response(data=serializer.validated_data,
        #                 status=status.HTTP_201_CREATED)


class ProjectInfoDetailGenericAPIView(GenericAPIView):
    """单个项目信息操作"""
    serializer_class = ProjectInfoSerializer
    queryset = Project.objects.all().order_by('-id')

    def get(self, request, pk):
        pass

    def put(self, request, pk):
        pass

    def delete(self, request, pk):
        pass


class PersonalProjectInfoGenericAPIView(GenericAPIView):
    """ 个人所有项目和增加项目 """
    serializer_class = ProjectInfoSerializer
    queryset = Project.objects.filter().select_related(
        'customer', 'creator').prefetch_related(
        'participants').order_by(
        '-id')
    permission_classes = [IsAuthenticated]
    pagination_class = LargeResultsSetPagination

    def get(self, request):
        # 获取查询集
        current_user = request.user
        # 筛选中当前登录用户的所有项目信息
        project_list = self.get_queryset().filter(
            Q(creator=current_user) | Q(participants=current_user)
        ).distinct()

        customer_info = request.query_params.get('customer_name')
        if customer_info:
            project_list = (project_list.filter
                            (Q(customer__name__icontains=customer_info) |
                             Q(SR_No__contains=customer_info)).distinct())
        # 继续筛选其它query_params, 可以 ** 展开
        search_params = {}
        # 筛选状态
        valid_status = ['Ongoing', 'Completed']
        status = request.query_params.get('status')
        if status in valid_status:
            search_params['status'] = status
        category = request.query_params.get('category')
        if category:
            search_params['category'] = category
        software = request.query_params.get('software')
        if software:
            search_params['software'] = software
        start_date = request.query_params.get('start_date')
        if start_date:
            search_params['start_date__gte'] = start_date
        end_date = request.query_params.get('end_date')
        if end_date:
            search_params['end_date__lte'] = end_date
        # 处理布尔值数据 request.query_params.get 返回 "true" 或 "false"（字符串）
        # 不是布尔类型 True 或 False, 需要对其进行处理
        big_project = request.query_params.get('big_project')
        # print('big_project', big_project, type(big_project))
        if big_project is not None:  # 确保 big_project 不是 None
            if big_project.lower() == 'true':  # 使用 lower() 以防大小写问题
                search_params['big_project'] = True
            elif big_project.lower() == 'false':
                # search_params['big_project'] = False
                # 如果 big_project 是 false，不添加它到 search_params
                # 这意味着不会应用 big_project 的过滤条件
                pass

        is_team_project = request.query_params.get('is_team_project')
        if is_team_project is not None:
            if is_team_project.lower() == 'true':
                search_params['is_team_project'] = True
            elif is_team_project.lower() == 'false':
                pass

        # print("Final search_params:", search_params)
        project_list = project_list.filter(**search_params)
        # 开始分页处理 对获得的查询集使用 paginate_queryset方法进行数据切片
        page_queryset = self.paginate_queryset(project_list)
        if page_queryset is not None:
            serializer = self.get_serializer(instance=page_queryset, many=True)
            # 使用 self.get_paginated_response(serializer.data)
            # 标准分页格式 {count, next, previous, results}  前端可获取分页状态
            return self.get_paginated_response(data=serializer.data)
        else:
            return Response(data=[])

    def post(self, request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 使用 data=serializer.data，因为结果有关联对象,不能JSON序列化，直接返回id
        return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        # return Response(data=serializer.validated_data,
        #                 status=status.HTTP_201_CREATED)


"""
select_related
作用：用于优化 一对一 (OneToOne) 和 多对一 (ForeignKey) 关系的查询，通过 SQL JOIN 一次性获取相关对象
原理：在数据库层面执行 JOIN 操作，将关联对象的数据一次性加载到内存中
示例：select_related('customer') 会通过 JOIN 一次性获取 Project 和对应的 Customer 数据
prefetch_related
作用：用于优化 多对多 (ManyToMany) 和 反向ForeignKey 关系的查询，执行额外的查询来获取相关对象
原理：先获取主对象，然后为每个关系执行单独的查询，最后在 Python 层面"拼接"结果
示例：prefetch_related('participants') 会先获取所有 Project，然后为每个 Project 执行查询获取其 participants
"""


class PersonalProjectInfoDetailGenericAPIView(GenericAPIView):
    """单个项目信息操作"""
    serializer_class = ProjectInfoSerializer
    queryset = Project.objects.all().select_related(
        'customer', 'creator').prefetch_related(
        'participants', 'activity_set').order_by(
        '-id')
    permission_classes = [IsAuthenticated]

    def get(self, request, pk):
        current_user = request.user
        try:
            project = self.get_object()
        except Exception as e:
            return Response(data={'error': '没有找到此项目！'},
                            status=status.HTTP_404_NOT_FOUND)
        # 处理participants多对多字段
        if (project.creator == current_user or
                project.participants.filter(id=current_user.id).exists()):

            # 序列化拿到项目信息
            project_serializer = self.get_serializer(instance=project)
            project_data = project_serializer.data

            # 继续获取项目下所有 activity 信息，activity_set反向查询， 并序列化。
            activities = project.activity_set.select_related('creator').all()
            if activities.exists():
                # 导入处理 activity的 序列化器
                # 延迟导入
                from sa.serializers.activitySerializer import ActivitySerializer
                # 再序列化 activities
                # context={'request': request} 的主要目的是让序列化器能够访问当前的 HTTP 请求对象。
                activity_serializer = ActivitySerializer(
                    instance=activities,
                    many=True,
                    context={'request': request}
                )
                activity_data = activity_serializer.data

                # 合并： 将activity_data 增加到 项目 project_data 里
                project_data['activities'] = activity_data

            return Response(data=project_data)

        else:
            logger.warning(
                f"用户 {current_user} 尝试查看无权限项目 ID:{pk} (创建者:{project.creator})")
            return Response(data={'error': '非创建者或参与者不能查看！'},
                            status=status.HTTP_403_FORBIDDEN)

    def put(self, request, pk):
        current_user = request.user
        try:
            project = self.get_object()
        except Exception as e:
            return Response(data={'error': '没有找到此项目！'},
                            status=status.HTTP_404_NOT_FOUND)
        if project.creator != current_user:
            logger.warning(
                f"用户 {current_user} 尝试修改无权限项目 ID:{pk} (创建者:{project.creator})")
            return Response(data={'error': '非创建者不能修改项目！'},
                            status=status.HTTP_403_FORBIDDEN)
        serializer = self.get_serializer(instance=project, data=request.data)
        # print('REQUEST_DATA:', request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        logger.info(f"用户 {current_user} 修改项目 ID:{pk} 成功！")
        # 使用 data=serializer.data，因为结果有关联对象,不能JSON序列化，直接返回id
        # print('SERIALIZER_DATA:', serializer.data)
        return Response(data=serializer.data, status=status.HTTP_200_OK)
        # return Response(data=serializer.validated_data,
        #                 status=status.HTTP_201_CREATED)

    def delete(self, request, pk):
        current_user = request.user
        try:
            # 获取目标项目
            instance = self.get_object()
        except Project.DoesNotExist:
            return Response(data={'error': '没有找到此项目！'},
                            status=status.HTTP_404_NOT_FOUND)
        # 检查创建者是否是当前登录用户
        if instance.creator != current_user:
            logger.warning(
                f"用户 {current_user} 尝试删除无权限项目 ID:{pk} (创建者:{instance.creator})")
            return Response(data={'error': '非创建者不能删除！'},
                            status=status.HTTP_403_FORBIDDEN)
        # 检查关联的activities
        activities = instance.activity_set.exists()
        if activities:
            return Response(data={
                'error': '此项目存在activity，不能直接删除！'
            }, status=status.HTTP_403_FORBIDDEN)
        # 执行删除
        instance.delete()
        logger.info(f"{current_user} 成功删除项目 {instance}")
        return Response(status=status.HTTP_204_NO_CONTENT)



"""
CustomerInfo._meta.get_field('region').choices 是 Django 模型系统中的一个高级用法，
用于动态获取模型字段的 `choices` 选项。解释：

CustomerInfo： Django 模型类。
_meta`：Django 在模型类中自动添加的属性，是 `django.db.models.options.Options` 的实例，包含模型的所有元数据（如字段、索引、权限等）。
get_field('region')：通过字段名获取该字段的 `Field` 对象（这里是 `CharField` 实例）。
.choices：访问字段的 `choices` 属性，返回定义的可选项元组。
"""


class ProjectCategoryChoicesAPIView(APIView):
    """获取工作分类option"""

    def get(self, request):
        category_choices = Project._meta.get_field('category').choices
        options = [{'value': value, 'label': label} for value, label in category_choices]
        # print(options)
        return Response(data=options)


class ProjectSoftwareChoicesAPIView(APIView):
    """获取软件option"""

    def get(self, request):
        software_choices = Project._meta.get_field('software').choices
        options = [{'value': value, 'label': label} for value, label in software_choices]
        return Response(data=options)


class ProjectLevelChoicesAPIView(APIView):
    """获取故障等级option"""

    def get(self, request):
        level_choices = Project._meta.get_field('level').choices
        # 列表推导式
        options = [{'value': value, 'label': label} for value, label in level_choices]
        return Response(data=options)


class ProjectStatusChoicesAPIView(APIView):
    """获取项目状态option"""

    def get(self, request):
        status_choices = Project._meta.get_field('status').choices
        # 列表推导式
        options = [{"value": value, "label": label} for value, label in status_choices]
        return Response(data=options)


class ProjectParticipantsChoicesAPIView(APIView):
    """ 多对多字段 """

    def get(self, request):
        # 返回 [(1, "admin"), (2, "user1"), (3, "user2")] 格式
        users = User.objects.exclude(cn_name='').values_list('id', 'cn_name')
        # 列表推导式
        options = [{'value': pk, 'label': cn_name} for pk, cn_name in users]
        return Response(data=options)
